﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Diagnostics;
using System.Linq;
using System.Linq.Dynamic;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using PortalWeb.Core.Entity;
using PortalWeb.Core.IDao;

namespace PortalWeb.Dao.Base
{
    /// <summary>
    /// 实现对数据库的操作(增删改查)的基类
    /// </summary>
    /// <typeparam name="T">定义泛型，约束其是一个类</typeparam>
    public class BaseRepository<T> : IBaseRepository<T> where T : class
    {
        //获取的是当前线程内部的上下文实例，而且保证了线程内上下文唯一
        public DbContext Context { get;protected set; }

        public BaseRepository(DbContext db)
        {
            Context = db;
        }

        long IBaseRepository<T>.Add(T entity)
        {
            throw new NotImplementedException();
        }

        public int Count()
        {
            return Context.Set<T>().Count();
        }
        public T Add(T entity, bool isSave = true)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }
            Context.Set<T>().Add(entity);
            if (isSave)
                Context.SaveChanges();
            return entity;
        }
       

        public T Find(dynamic primaryId)
        {
            return Context.Set<T>().Find(primaryId);
        }

        public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
        {
            throw new NotImplementedException();
        }

        public async Task<IEnumerable<T>> FindAllAsync()
        {
            return await Context.Set<T>().ToArrayAsync();
        }

        public async Task<IEnumerable<T>> FindAsync(Expression<Func<T, bool>> predicate)
        {
            var result = Context.Set<T>().Where(predicate);
            return await result.ToArrayAsync();
        }

        public Task<T> FindAsync(dynamic primaryId)
        {
            return Context.Set<T>().FindAsync(primaryId);
        }

        public IEnumerable<T> Where(Func<T, bool> func)
        {
            return  Context.Set<T>().Where(func) as IEnumerable<T>;
        }

        public long Add(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }
            Context.Set<T>().Add(entity);
            return SaveChanges();
        }

        /// <summary>
        /// 实现对数据库的添加功能,添加实现EF框架的引用
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<int> AddAsync(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }
            Context.Set<T>().Add(entity);
            return await SaveChangesAsync();
        }

        public async Task<T> UpdateAsync(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }
            Context.Set<T>().Attach(entity);
            Context.Entry<T>(entity).State = EntityState.Modified;
            var b = await SaveChangesAsync();
            if (b > 0)
            {
                return entity;
            }
            else
            {
                return null;
            }
        }

        public async Task<bool> DeleteAsync(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }
            Context.Set<T>().Attach(entity);
            Context.Entry<T>(entity).State = EntityState.Deleted;
            var b = await SaveChangesAsync();
            return b > 0;
        }

        /// <summary>
        /// 保存执行
        /// </summary>
        /// <returns></returns>
        async Task<int> SaveChangesAsync()
        {
            return await Context.SaveChangesAsync();
        }

        /// <summary>
        /// 保存执行
        /// </summary>
        /// <returns></returns>
        public int SaveChanges()
        {
            return Context.SaveChanges();
        }

        public bool Update(T entity, bool isSave = true)
        {
            Context.Set<T>().Attach(entity);
            Context.Entry<T>(entity).State = EntityState.Modified;

            return !isSave || Context.SaveChanges() > 0;
        }

        public bool Delete(IList<T> entityList, bool isSave = true)
        {
            foreach (var entity in entityList)
            {
                Context.Set<T>().Attach(entity);
                Context.Entry<T>(entity).State = EntityState.Deleted;
            }
            return !isSave || Context.SaveChanges() > 0;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="isSave"></param>
        /// <returns></returns>
        public bool Delete(T entity, bool isSave = true)
        {
            Context.Set<T>().Attach(entity);
            Context.Entry<T>(entity).State = EntityState.Deleted;
            return !isSave || Context.SaveChanges() > 0;
        }


        public int Count(Expression<Func<T, bool>> predicate)
        {
            return Context.Set<T>().Count(predicate);
        }

        public bool Exist(Expression<Func<T, bool>> anyLambda)
        {
            return Context.Set<T>().Any(anyLambda);
        }



        public virtual async Task<T[]> LoadPageEntitiesAsync<TS>(Expression<Func<T, bool>> whereLambda,
            bool isAsc, Expression<Func<T, TS>> orderByLambda, int offset, int limit)
        {
            var temp = Context.Set<T>().Where<T>(whereLambda);
            //排序,获取当前页的数据
            if (isAsc)
            {
                return await temp.OrderBy(orderByLambda)
                    .Skip(offset) //越过多少条
                    .Take(limit - offset).ToArrayAsync(); //取出多少条
            }
            else
            {
                return await temp.OrderByDescending(orderByLambda)
                    .Skip(offset) //越过多少条
                    .Take(limit - offset).ToArrayAsync(); //取出多少条
            }
        }

        [DebuggerStepThrough]
        public virtual async Task<T[]> LoadPageEntitiesnAsync(Expression<Func<T, bool>> whereLambda, string order, string sort, int offset, int limit)
        {
            this.ThrowIfDisposed();
            return await Context.Set<T>().Where(whereLambda)
                .OrderBy(sort + " " + order)
                .Skip(offset)
                .Take(limit - offset).ToArrayAsync();
        }

        [DebuggerStepThrough]
        public virtual async Task<T[]> LoadEntitiesnAsync(Expression<Func<T, bool>> whereLambda)
        {
            this.ThrowIfDisposed();
            return await Context.Set<T>().Where(whereLambda).ToArrayAsync();
        }

        /// <summary>
        /// 实现对数据的分页查询
        /// </summary>
        /// <typeparam name="TS">按照某个类进行排序</typeparam>
        /// <param name="whereLambda">取得排序的条件</param>
        /// <param name="isAsc">如何排序，根据倒叙还是升序</param>
        /// <param name="orderByLambda">根据那个字段进行排序</param>
        /// <returns></returns>
        public T[] LoadPageEntities<TS>(Expression<Func<T, bool>> whereLambda, bool isAsc, Expression<Func<T, TS>> orderByLambda, int offset, int limit)
        {
            var temp = Context.Set<T>().Where<T>(whereLambda);
            //排序,获取当前页的数据
            if (isAsc)
            {
                return temp.OrderBy(orderByLambda)
                    .Skip(offset) //越过多少条
                    .Take(limit - offset).ToArray(); //取出多少条
            }
            else
            {
                return temp.OrderByDescending(orderByLambda)
                    .Skip(offset) //越过多少条
                    .Take(limit - offset).ToArray(); //取出多少条
            }
        }


        public T[] LoadPageEntities(Expression<Func<T, bool>> whereLambda, string order, string sort, int offset,
            int limit)
        {
            return Context.Set<T>().Where(whereLambda)
                .OrderBy(sort + " " + order)
                .Skip(offset)
                .Take(limit - offset).ToArray();
        }

        protected void ThrowIfDisposed()
        {
            if (this._disposed)
            {
                throw new ObjectDisposedException("BaseRepository");
            }
        }

        private bool _disposed;

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing && !this._disposed)
            {
                Context.Dispose();
                this._disposed = true;
            }
        }

  
    }
}